package com.zong.coder.controller;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import com.zong.core.bean.DataMap;
import com.zong.core.bean.Result;
import com.zong.core.controller.BaseController;
import com.zong.core.exception.ServiceException;
import com.zong.core.util.JsoupUtil;
import com.zong.zdb.service.JdbcCodeService;
import com.zong.zdb.util.PageData;

/**
 * @desc rest接口测试客户端页面，基于spring restTemplate
 * @author zong
 * @date 2019年4月30日
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
@Controller
@RequestMapping("/restclient")
public class RestTemplateController extends BaseController {
	private Logger logger = Logger.getLogger(RestTemplateController.class);
	// 模拟浏览器访问
	public static final String USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31";
	private static final RestTemplate restTemplate = getRestTemplate();
	private JdbcCodeService codeService = JdbcCodeService.getInstance();

	private static RestTemplate getRestTemplate() {
		RestTemplate restTemplate = new RestTemplate();
		// 默认ISO-8859-1，需要指定UTF-8否则中文乱码
		restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
		return restTemplate;
	}

	@RequestMapping
	public String restclient(Model model) {
		model.addAttribute("nav", "rest");
		return "/coder/restclient";
	}

	@ResponseBody
	@RequestMapping(value = "/request", method = RequestMethod.POST)
	public Result request(@RequestBody DataMap request) {
		Result result = new Result("errMsg", "success");
		try {
			String method = request.getString("method");
			String url = request.getString("url");
			Map headers = (Map) request.get("headers");
			Map params = (Map) request.get("params");
			String contentType = (String) headers.get("Content-Type");
			// 期望获得数据格式，根据后缀判断
			String accept = (String) headers.get("Accept");
			if (accept == null) {
				String location = url.split("\\?")[0];
				if (location.lastIndexOf(".") >= 0) {
					String suffix = location.substring(location.lastIndexOf(".")).replace(".", "");
					if (suffix.equals("json")) {
						accept = "application/json; charset=utf-8";
					} else if (suffix.equals("xml")) {
						accept = "application/xml; charset=utf-8";
					}
				}
				if (accept != null) {
					headers.put("Accept", accept);
				}
			}
			HttpHeaders httpHeaders = new HttpHeaders();
			for (Object k : headers.keySet()) {
				httpHeaders.add(k.toString(), headers.get(k).toString());
			}
			if (headers.get("User-Agent") == null) {
				httpHeaders.add("User-Agent", USER_AGENT);
			}
			ResponseEntity response = null;
			if (method.equals("GET")) {
				response = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity(httpHeaders), String.class);
			} else {
				HttpMethod m = null;
				if (method.equals("POST")) {
					m = HttpMethod.POST;
				} else if (method.equals("PUT")) {
					m = HttpMethod.PUT;
				} else if (method.equals("DELETE")) {
					m = HttpMethod.DELETE;
				}
				if (contentType.equals("form-data")) {
					MediaType type = MediaType.parseMediaType(MediaType.MULTIPART_FORM_DATA_VALUE);
					httpHeaders.setContentType(type);
					MultiValueMap<String, Object> form = new LinkedMultiValueMap<String, Object>();
					for (Object key : params.keySet()) {
						String[] arr = params.get(key).toString().split("\\|");
						String fieldType = arr[0];
						if (fieldType.equals("text")) {
							form.add(key.toString(), arr[1]);
						} else {// 有文件参数且存在文件则取出地址，从服务器读出来提交
							if (arr.length == 3) {
								String filePath = getRealPath() + arr[2];
								form.add(key.toString(), new FileSystemResource(filePath));
							}
						}
					}
					response = restTemplate.exchange(url, m,
							new HttpEntity<MultiValueMap<String, Object>>(form, httpHeaders), String.class);
				} else if (contentType.equals("x-www-form-urlencoded")) {
					MediaType type = MediaType.parseMediaType(MediaType.APPLICATION_FORM_URLENCODED_VALUE);
					httpHeaders.setContentType(type);
					MultiValueMap<String, Object> form = new LinkedMultiValueMap<String, Object>();
					for (Object k : params.keySet()) {
						form.add(k.toString(), params.get(k));
					}
					response = restTemplate.exchange(url, m,
							new HttpEntity<MultiValueMap<String, Object>>(form, httpHeaders), String.class);
				} else {
					MediaType type = MediaType.parseMediaType(contentType);
					httpHeaders.setContentType(type);
					response = restTemplate.exchange(url, m,
							new HttpEntity<String>((String) params.get("payload"), httpHeaders), String.class);
				}
			}
			Result data = new Result("body", response.getBody());
			Result headersData = new Result();
			HttpHeaders hs = response.getHeaders();
			for (String key : hs.keySet()) {
				headersData.put(key, hs.getFirst(key));
				if (key.toLowerCase().equals("set-cookie")) {
					Result cookies = new Result();
					String[] arr = hs.getFirst(key).split(";");
					for (String value : arr) {
						value = value.trim();
						if (!value.equals("")) {
							String[] arrs = value.split("=");
							cookies.put(arrs[0], arrs.length > 1 ? arrs[1] : "");
						}
					}
					data.put("cookies", cookies);
				}
			}
			data.put("headers", headersData);
			data.put("statusCode", response.getStatusCode().value());
			data.put("statusText", response.getStatusCode().getReasonPhrase());
			result.put("data", data);
		} catch (Exception e) {
			logger.error(e.toString(), e);
			result.put("errMsg", e.getMessage());
		}
		return result;
	}

	/**
	 * 上传附件
	 * 
	 */
	@ResponseBody
	@RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
	public Result uploadFile(MultipartFile file) {
		Result result = Result.success();
		try {
			String path = "upload/restTemp/" + file.getOriginalFilename();
			File f = new File(getRealPath() + path);
			if (!f.getParentFile().exists()) {
				f.getParentFile().mkdirs();
			}
			file.transferTo(f);
			result.put("fileName", file.getOriginalFilename());
			result.put("url", path);
		} catch (Exception e) {
			logger.error(e.toString(), e);
			result.error(e);
		}
		return result;
	}

	/**
	 * 解析列表页面
	 * 
	 * @param craw_url   抓取地址【必须】
	 * @param craw_item  条目规则【必须】
	 * @param craw_next  下一页规则
	 * @param craw_store 存储表名，只有指定才保存到数据库
	 * @param exts       非craw_*关键参数的其他扩展规则
	 */
	@ResponseBody
	@RequestMapping("/crawList")
	public Result crawList(String craw_store) {
		Result result = Result.success();
		try {
			Result r = JsoupUtil.parseList(getPageData());
			saveData(craw_store, r);
			result.put("data", r.get("data"));
			result.put(JsoupUtil.CRAW_NEXT, r.get(JsoupUtil.CRAW_NEXT));
		} catch (ServiceException e) {
			result.error(e);
		} catch (Exception e) {
			logger.error(e.toString(), e);
			result.error(e);
		}
		return result;
	}

	private void saveData(String craw_store, Result result) throws Exception {
		if (craw_store == null || "".equals(craw_store)) {
			return;
		}
		String[] arr = craw_store.split(";");
		List<Result> list = (List<Result>) result.get("data");
		for (Result data : list) {
			PageData pd = new PageData();
			for (Object key : data.keySet()) {
				pd.put(key, data.get(key));
			}
			codeService.insert(arr[0], arr[1], pd);
		}
	}
}
